library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;


entity execution_stage is
generic (numBit 	: integer := 32;
			shamtSize: integer := 5);
port(	clk 			: in  std_logic;
		rst 			: in  std_logic;
		enb 			: in  std_logic;
		NewPC 		: in  std_logic_vector (numBit-1 downto 0);	-- Program Counter + 4
		A_reg 		: in  std_logic_vector (numBit-1 downto 0);	-- first register from the register file
		B_reg 		: in  std_logic_vector (numBit-1 downto 0);	-- second register from the register file
		Imm_reg		: in  std_logic_vector (numBit-1 downto 0);	-- immediate register
		shamt_in		: in  std_logic_vector (shamtSize-1 downto 0);
		operation	: in  std_logic_vector (3 downto 0);	--operation to be executed	
		info_in		: in  std_logic;	
		types_in 	: in  std_logic;
		extra_in 	: in  std_logic;
		mux_l_pilot : in  std_logic;	
		mux_r_pilot : in  std_logic;	
		cmp_pilot	: in  std_logic_vector (2 downto 0);
		ALU_output 	: out std_logic_vector (numBit-1 downto 0);
		branch 		: out std_logic;								-- last program counter mux pilot
		status		: out std_logic
);
end execution_stage;

architecture Structural of execution_stage is

component muxer
generic (N : integer := 32);
port(	data_0 : in  std_logic_vector (N-1 downto 0);
		data_1 : in  std_logic_vector (N-1 downto 0);
		sel 	 : in  std_logic;
		output : out std_logic_vector (N-1 downto 0)
);
end component;

component reg is
generic (N : integer :=32);
port( clock		: in  std_logic;
		reset		: in  std_logic;
		enable	: in  std_logic;
		data_in 	: in  std_logic_vector (N-1 downto 0);
		data_out : out std_logic_vector (N-1 downto 0)
);
end component;

component arithmetic_logic_unit is
generic (N : integer := 32;
			M : integer := 5);
port(	left		: in  std_logic_vector (N-1 downto 0);	-- left operand (A or NPC)
		right		: in  std_logic_vector (N-1 downto 0);	-- right operand (B or Imm)
		alu_mux	: in  std_logic_vector (3 downto 0);	-- operation to perform (activates the correct output)
		sh_amt	: in  std_logic_vector (M-1 downto 0);	-- shift amount
		info 		: in  std_logic;								-- signed/unsigned, positive/negative, left/right
		types		: in  std_logic;								-- addition/subtraction, logical/arithmetical
		extra		: in  std_logic;								-- shift/rotate, logical-op
		output	: out std_logic_vector (N-1 downto 0);	-- ALU output
		status	: out std_logic								-- unused (should set the OF flag)
);
end component;

component checker is
generic (N : integer := 32);
port(	data_in 	: in  std_logic_vector (N-1 downto 0);
		cmp_need	: in  std_logic_vector (2 downto 0);
		sel		: out std_logic
);
end component;

signal ALU_in_l 		: std_logic_vector (numBit-1 downto 0);
signal ALU_in_r 		: std_logic_vector (numBit-1 downto 0); 
signal ALU_out  		: std_logic_vector (numBit-1 downto 0);
signal i_status		: std_logic;				-- unused

begin

MUX_L : muxer generic map(numBit) port 
map (	data_0	=> A_reg,
		data_1	=> NewPC,
		sel 		=> mux_l_pilot,
		output	=> ALU_in_l
);

MUX_R : muxer generic map(numBit) port 
map (	data_0	=> B_reg,
		data_1	=> Imm_reg,
		sel 		=> mux_r_pilot,
		output 	=> ALU_in_r
);

ALU: arithmetic_logic_unit generic map(numBit,shamtSize) port
map (	left		=> ALU_in_l,
		right		=> ALU_in_r,
		alu_mux	=> operation,
		sh_amt	=> shamt_in,
		info 		=> info_in,
		types		=> types_in,
		extra		=> extra_in,
		output	=> ALU_out,
		status	=> i_status						-- unused (should set the OF flag)
);

CHK: checker generic map (numBit) port
map (	data_in 	=> A_reg,
		cmp_need	=> cmp_pilot,
		sel		=> branch
);

ALU_reg: reg generic map(numBit) port
map (	clock		=> clk,
		reset		=> rst,
		enable	=> enb,
		data_in  => ALU_out,
		data_out => ALU_output
);

status <= i_status;

end Structural;
